# install.packages("ggplot2","dplyr")
library(ggplot2)
library(dplyr)
library(tidyr)

The purpose of this notebook is to demonstrate some of what is possible for visualisation of a text. Quantitative analysis is a tool that can help to answer some questions, but it is not always useful and there are many questions it cannot address. I hope to demonstrate below some of the things that can be done, and hopefully it will be more inspiring that intimidating.

Reading in corpus

First, there must be a corpus or digitized text that can be analysed computationally. For this demonstration, I’ve used a corpus of Shakespeare’s plays and adapted some code from a Kaggle notebook.

# R must be at least 3.3.1 for `tm` and `slam` to work.
# install.packages("tm")
# install.packages("SnowballC")
library(tm)
#system("ls ../input") # do we need this?

Before we get into anything fun, we have to see what the corpus looks like; that is, how the data frame is structured. These are the first six lines of the corpus. NB: there is currently a small bug in the software that prevents the data from being shown neatly. It should be fixed soon.

#shak<-na.omit(shak)
head(shak)
  Dataline     Play PlayerLinenumber ActSceneLine        Player
1        1 Henry IV               NA                           
2        2 Henry IV               NA                           
3        3 Henry IV               NA                           
4        4 Henry IV                1        1.1.1 KING HENRY IV
5        5 Henry IV                1        1.1.2 KING HENRY IV
6        6 Henry IV                1        1.1.3 KING HENRY IV
                                                                                        PlayerLine
1                                                                                            ACT I
2                                                                     SCENE I. London. The palace.
3 Enter KING HENRY, LORD JOHN OF LANCASTER, the EARL of WESTMORELAND, SIR WALTER BLUNT, and others
4                                                           So shaken as we are, so wan with care,
5                                                       Find we a time for frighted peace to pant,
6                                                   And breathe short-winded accents of new broils

Each column is labeled and the content of the column is consistent for each row (all 111396 of them!). Some of the rows may not be useful. Some contain empty cells (labeled NA). Some contain a lot of information and we might need to do some processing on them before we can use the information quantitatively.

Word frequency

The first thing we’ll look at is word frequency, or how often a string (in this case “love”) occurs in the data frame. To do this, we must identify every time the word “love” appears and highlight it in a way so that it can be counted based on different properties of its environment (e.g., by play, by player, by scene, etc).

Here are the first 10 rows of a data frame that contains the number of times “love” appears in each play. It’s been sorted in descending order, but doesn’t contain any other information about where and when the word occurs.

head(lPlay,10)
                      plays loveFreq
35  Two Gentlemen of Verona      188
28         Romeo and Juliet      160
6            As you like it      138
22 A Midsummer nights dream      128
17       Loves Labours Lost      125
23   Much Ado about nothing      122
24                  Othello      108
33     Troilus and Cressida       87
27              Richard III       86
11                   Hamlet       85

We can also look at which players say “love” the most over the course of their appearences. These are only the top 10 players who use the word “love” most.

head(lPlayer,10)
       players loveFreq
904    PROTEUS       59
190   ROSALIND       57
771      ROMEO       56
169     HELENA       46
906      JULIA       41
650       IAGO       40
572     JULIET       37
38  GLOUCESTER       36
517      BIRON       36
639   BENEDICK       36

We can also look at the bottom of the list. These are 10 players who only say “love” once, although there are likely many others who are also tied for last.

tail(lPlayer,10)
           players loveFreq
890        CALCHAS        1
899 SIR TOBY BELCH        1
903         FABIAN        1
914   Third Outlaw        1
917     ARCHIDAMUS        1
922      MAMILLIUS        1
925        PAULINA        1
932        PERDITA        1
933         DORCAS        1
934          MOPSA        1

Is this useful to you? Can word frequency by character/player, scene, act, play, or author help to answer any of your research questions?

Visualising a corpus

I think the main way quantitative analysis can be of use to the humanities is by visualising properties of the text that might not be immediately apparent from reading. Word frequency is one of these properties, since we (as humans) don’t typically keep track of how often each characters says any given word. If you’re interested in how different characters or different authors make use of certain words or phrases, visualising the distribution of those strings might uncover patterns that are otherwise difficult to find.

For instance, maybe you are curious how the longer and shorter plays compare. Instead of hand-counting each, we can graph and order them. Based on this graph, you don’t need to know exactly how long each is, but you can see that Othello is much longer than Loves Labours Lost, which can inform how you approach the comparison.

shak %>%
  group_by(Play) %>%
  summarise(n = n()) %>%
  ggplot(., aes(x=reorder(Play, n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip() +
    ggtitle("Length of Shakespeare's plays") +
    theme(legend.position="none") +
    xlab("Play") +
    ylab("Number of lines")

Within a single play, maybe we want to know which characters are the chattiest. We can visualise the number of lines of text per character to get a sense of who is dominating the stage.

shak %>%
  filter(Play == "Hamlet") %>%
  group_by(Player) %>%
  summarise(n = n()) %>%
  ggplot(., aes(x=reorder(Player, n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip() +
    ggtitle("Speech in Hamlet") +
    theme(legend.position="none") +
    xlab("Player") +
    ylab("Number of lines")

Obviously, it’s Hamlet.

shak %>%
  group_by(Play,Player) %>%
  summarise(n = n()) %>%
  filter(n > 700) %>%
  ggplot(., aes(x=reorder(Player, n),y=n)) +
    geom_bar(aes(fill=Play),stat="identity") +
    coord_flip() +
    ggtitle("Amount of lines by character") +
#    theme(legend.position="none") +
    xlab("Player") +
    ylab("Number of lines")

lPlay %>%
  ggplot(., aes(x=reorder(plays, loveFreq),y=loveFreq)) +
    geom_bar(aes(fill=plays),stat="identity") +
    coord_flip() +
    ggtitle("Love in each play") +
#    theme(legend.position="none") +
    xlab("Play") +
    ylab("frequency of the word 'love'") +
    theme(legend.position = "none")

lPlayer %>%
  filter(loveFreq > 20) %>%
  ggplot(., aes(x=reorder(players, loveFreq),y=loveFreq)) +
    geom_bar(aes(fill=players),stat="identity") +
    coord_flip() +
    ggtitle("Love in each play") +
#    theme(legend.position="none") +
    xlab("Play") +
    ylab("frequency of the word 'love'") +
    theme(legend.position = "none")

Attempting n-grams

library(dplyr)
#install.packages("tidytext")
library(tidytext)
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word)
# A tibble: 820,204 x 6
   Dataline Play     PlayerLinenumber ActSceneLine Player word  
      <int> <chr>               <int> <chr>        <chr>  <chr> 
 1        1 Henry IV               NA ""           ""     act   
 2        1 Henry IV               NA ""           ""     i     
 3        2 Henry IV               NA ""           ""     scene 
 4        2 Henry IV               NA ""           ""     i     
 5        2 Henry IV               NA ""           ""     london
 6        2 Henry IV               NA ""           ""     the   
 7        2 Henry IV               NA ""           ""     palace
 8        3 Henry IV               NA ""           ""     enter 
 9        3 Henry IV               NA ""           ""     king  
10        3 Henry IV               NA ""           ""     henry 
# ... with 820,194 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  count(word, sort = TRUE)
# A tibble: 24,749 x 2
   word      n
   <chr> <int>
 1 the   27052
 2 and   25082
 3 i     20142
 4 to    18984
 5 of    15862
 6 a     14196
 7 you   13347
 8 my    11875
 9 in    10540
10 that  10441
# ... with 24,739 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  anti_join(stop_words) %>%
  count(word, sort = TRUE)
Joining, by = "word"
# A tibble: 24,148 x 2
   word      n
   <chr> <int>
 1 thou   5193
 2 thy    3727
 3 thee   3024
 4 lord   2621
 5 sir    2454
 6 enter  2338
 7 love   1927
 8 hath   1845
 9 king   1500
10 tis    1384
# ... with 24,138 more rows
shak %>%
  as_tibble(.) %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  anti_join(stop_words) %>%
  count(word, sort = TRUE) %>%
  filter(n>800) %>%
  ggplot(., aes(x=reorder(word,n),y=n)) +
    geom_bar(stat="identity") +
    coord_flip()
Joining, by = "word"

Using tibbles

How can we organise this so that we can compare across plays?

shak[,c(2,5,6)] %>%
  as_tibble() %>%
  unnest_tokens(tbl=., input = PlayerLine, output = word) %>%
  filter(word=="love" | word =="king" | word=="death" | word=="sweet") %>%
  #add_count(Player) %>%
  group_by(Player,Play,word) %>%
  summarise(n=n()) %>%
  #anti_join(stop_words) %>%
  filter(  Play == "Hamlet" | 
           Play == "King Lear" | 
           Play == "A Midsummer nights dream" | 
           Play == "Othello" | 
           Play == "Henry V" | 
           Play == "Romeo and Juliet") %>%
  arrange(desc(n)) %>%
  ggplot(., aes(x=word,y=n)) +
    geom_bar(aes(fill=word),stat="identity") +
#    coord_flip() +
    facet_wrap(~Play)

Is there a way to break it down to see who is saying what?

What about n-grams

word <- c(NA,"thou","thee","thy","thine","dost","shalt","wilt","hast","hath","scene","tis","ii","iii","iv","v","vi","vii")
lexicon <- rep("shakespeare",length(word))
new_stop <- cbind(word,lexicon)
shak_stop <- rbind(new_stop,stop_words)
shak %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE)
# A tibble: 57,371 x 3
   word1    word2       n
   <chr>    <chr>   <int>
 1 enter    king      101
 2 mine     eyes       95
 3 king     henry      88
 4 sir      john       80
 5 mark     antony     76
 6 mine     honour     71
 7 king     richard    51
 8 god      save       48
 9 gracious lord       46
10 noble    lord       46
# ... with 57,361 more rows

Networks

#install.packages("igraph")
#install.packages("ggraph")
library(igraph)
library(ggraph)
library(grid)

Bigrams

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
p1 <- shak %>%
  filter(Play=="Hamlet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
set.seed(814)
p2 <- shak %>%
  filter(Play == "Twelfth Night") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkred", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "salmon", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
set.seed(814)
p3 <- shak %>%
  filter(Play == "Romeo and Juliet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 6) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkgreen", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "green2", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()
multiplot(p1,p2,p3,cols=3)

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
p1 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play=="Hamlet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Hamlet")
set.seed(814)
p2 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Twelfth Night") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkred", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "salmon", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Twelfth Night")
set.seed(814)
p3 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Romeo and Juliet") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkgreen", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "green2", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Romeo and Juliet")
set.seed(814)
p4 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Othello") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkorange", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "orange", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Othello")
set.seed(814)
p5 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "Henry IV") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="cadetblue4", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "cyan", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("Henry IV")
set.seed(814)
p6 <- shak %>%
  filter(ActSceneLine != "") %>%
  filter(Play == "The Tempest") %>%
  as_tibble() %>%
  unnest_tokens(input = PlayerLine, output = bigram, token = "ngrams", n = 2) %>%
  separate(bigram, c("word1", "word2"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  count(word1, word2, sort = TRUE) %>%
  filter(n > 3) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="violet", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "magenta", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void() +
    ggtitle("The Tempest")
multiplot(p1,p2,p3,p4,p5,p6,cols=3)

Trigrams

This should give us a better idea of slightly looser connections

set.seed(814)
a <- grid::arrow(type = "closed", angle=22.5, length = unit(.1, "inches"))
shak %>%
  as_tibble() %>%
  filter(ActSceneLine != "") %>%
  unnest_tokens(input = PlayerLine, output = trigram, token = "ngrams", n = 3) %>%
  separate(trigram, c("word1", "word2", "word3"), sep = " ") %>% # separates bigram into two columns, one for each word
  filter(!word1 %in% shak_stop$word) %>% # filters stop words from first column
  filter(!word2 %in% shak_stop$word) %>% # filters stop words from second column
  filter(!word3 %in% shak_stop$word) %>% # filters stop words from third column
  count(word1, word2, word3, sort = TRUE) %>%
  filter(n > 2) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
    geom_edge_link(aes(edge_alpha = n), edge_colour="darkblue", show.legend = FALSE,
                 arrow = a, end_cap = circle(.07, 'inches')) +
    geom_node_point(color = "lightblue", size = 5) +
    geom_node_text(aes(label = name), repel=TRUE) + # , vjust = 1, hjust = 1) +
    theme_void()

What happens if we treat the first pair and second pair of trigrams as separate bigrams and graph them as before?

Heatmaps

shak %>%
  as_tibble() %>%
  #filter(Play == "Hamlet" | Play == "Loves Labours Lost" | Play == "A Winters Tale") %>%
  filter(ActSceneLine != "") %>%
  mutate(ActSceneLine2 = ActSceneLine) %>%
  separate(ActSceneLine2, c("act", "scene", "line")) %>%
  count(Play,act,scene, sort=TRUE) %>%
  transmute(play=Play, act=as.numeric(act), scene=as.numeric(scene), n=n)
# A tibble: 737 x 4
   play                  act scene     n
   <chr>               <dbl> <dbl> <int>
 1 Loves Labours Lost      5     2   972
 2 A Winters Tale          4     4   929
 3 Hamlet                  2     2   616
 4 King John               2     1   609
 5 The Tempest             1     2   596
 6 Cymbeline               5     5   584
 7 Measure for measure     5     1   580
 8 Timon of Athens         4     3   577
 9 Richard III             4     4   561
10 A Winters Tale          1     2   539
# ... with 727 more rows

Wrap up

What this all seems to tell us is that we can visualise the structure of the play, separate from their content. Is this useful to you?

LS0tCnRpdGxlOiAiUHJvY2Vzc2luZyBTaGFrZXNwZWFyZSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KIyBNdWx0aXBsZSBwbG90IGZ1bmN0aW9uCiMKIyBnZ3Bsb3Qgb2JqZWN0cyBjYW4gYmUgcGFzc2VkIGluIC4uLiwgb3IgdG8gcGxvdGxpc3QgKGFzIGEgbGlzdCBvZiBnZ3Bsb3Qgb2JqZWN0cykKIyAtIGNvbHM6ICAgTnVtYmVyIG9mIGNvbHVtbnMgaW4gbGF5b3V0CiMgLSBsYXlvdXQ6IEEgbWF0cml4IHNwZWNpZnlpbmcgdGhlIGxheW91dC4gSWYgcHJlc2VudCwgJ2NvbHMnIGlzIGlnbm9yZWQuCiMKIyBJZiB0aGUgbGF5b3V0IGlzIHNvbWV0aGluZyBsaWtlIG1hdHJpeChjKDEsMiwzLDMpLCBucm93PTIsIGJ5cm93PVRSVUUpLAojIHRoZW4gcGxvdCAxIHdpbGwgZ28gaW4gdGhlIHVwcGVyIGxlZnQsIDIgd2lsbCBnbyBpbiB0aGUgdXBwZXIgcmlnaHQsIGFuZAojIDMgd2lsbCBnbyBhbGwgdGhlIHdheSBhY3Jvc3MgdGhlIGJvdHRvbS4KIwptdWx0aXBsb3QgPC0gZnVuY3Rpb24oLi4uLCBwbG90bGlzdD1OVUxMLCBmaWxlLCBjb2xzPTEsIGxheW91dD1OVUxMKSB7CiAgbGlicmFyeShncmlkKQoKICAjIE1ha2UgYSBsaXN0IGZyb20gdGhlIC4uLiBhcmd1bWVudHMgYW5kIHBsb3RsaXN0CiAgcGxvdHMgPC0gYyhsaXN0KC4uLiksIHBsb3RsaXN0KQoKICBudW1QbG90cyA9IGxlbmd0aChwbG90cykKCiAgIyBJZiBsYXlvdXQgaXMgTlVMTCwgdGhlbiB1c2UgJ2NvbHMnIHRvIGRldGVybWluZSBsYXlvdXQKICBpZiAoaXMubnVsbChsYXlvdXQpKSB7CiAgICAjIE1ha2UgdGhlIHBhbmVsCiAgICAjIG5jb2w6IE51bWJlciBvZiBjb2x1bW5zIG9mIHBsb3RzCiAgICAjIG5yb3c6IE51bWJlciBvZiByb3dzIG5lZWRlZCwgY2FsY3VsYXRlZCBmcm9tICMgb2YgY29scwogICAgbGF5b3V0IDwtIG1hdHJpeChzZXEoMSwgY29scyAqIGNlaWxpbmcobnVtUGxvdHMvY29scykpLAogICAgICAgICAgICAgICAgICAgIG5jb2wgPSBjb2xzLCBucm93ID0gY2VpbGluZyhudW1QbG90cy9jb2xzKSkKICB9CgogaWYgKG51bVBsb3RzPT0xKSB7CiAgICBwcmludChwbG90c1tbMV1dKQoKICB9IGVsc2UgewogICAgIyBTZXQgdXAgdGhlIHBhZ2UKICAgIGdyaWQubmV3cGFnZSgpCiAgICBwdXNoVmlld3BvcnQodmlld3BvcnQobGF5b3V0ID0gZ3JpZC5sYXlvdXQobnJvdyhsYXlvdXQpLCBuY29sKGxheW91dCkpKSkKCiAgICAjIE1ha2UgZWFjaCBwbG90LCBpbiB0aGUgY29ycmVjdCBsb2NhdGlvbgogICAgZm9yIChpIGluIDE6bnVtUGxvdHMpIHsKICAgICAgIyBHZXQgdGhlIGksaiBtYXRyaXggcG9zaXRpb25zIG9mIHRoZSByZWdpb25zIHRoYXQgY29udGFpbiB0aGlzIHN1YnBsb3QKICAgICAgbWF0Y2hpZHggPC0gYXMuZGF0YS5mcmFtZSh3aGljaChsYXlvdXQgPT0gaSwgYXJyLmluZCA9IFRSVUUpKQoKICAgICAgcHJpbnQocGxvdHNbW2ldXSwgdnAgPSB2aWV3cG9ydChsYXlvdXQucG9zLnJvdyA9IG1hdGNoaWR4JHJvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQucG9zLmNvbCA9IG1hdGNoaWR4JGNvbCkpCiAgICB9CiAgfQp9CmBgYAoKCmBgYHtyLG1lc3NhZ2U9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIsImRwbHlyIikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpgYGAKCgpUaGUgcHVycG9zZSBvZiB0aGlzIG5vdGVib29rIGlzIHRvIGRlbW9uc3RyYXRlIHNvbWUgb2Ygd2hhdCBpcyBwb3NzaWJsZSBmb3IgdmlzdWFsaXNhdGlvbiBvZiBhIHRleHQuIFF1YW50aXRhdGl2ZSBhbmFseXNpcyBpcyBhIHRvb2wgdGhhdCBjYW4gaGVscCB0byBhbnN3ZXIgc29tZSBxdWVzdGlvbnMsIGJ1dCBpdCBpcyBub3QgYWx3YXlzIHVzZWZ1bCBhbmQgdGhlcmUgYXJlIG1hbnkgcXVlc3Rpb25zIGl0IGNhbm5vdCBhZGRyZXNzLiBJIGhvcGUgdG8gZGVtb25zdHJhdGUgYmVsb3cgc29tZSBvZiB0aGUgdGhpbmdzIHRoYXQgY2FuIGJlIGRvbmUsIGFuZCBob3BlZnVsbHkgaXQgd2lsbCBiZSBtb3JlIGluc3BpcmluZyB0aGF0IGludGltaWRhdGluZy4gCgojIFJlYWRpbmcgaW4gY29ycHVzCgpGaXJzdCwgdGhlcmUgbXVzdCBiZSBhIGNvcnB1cyBvciBkaWdpdGl6ZWQgdGV4dCB0aGF0IGNhbiBiZSBhbmFseXNlZCBjb21wdXRhdGlvbmFsbHkuIEZvciB0aGlzIGRlbW9uc3RyYXRpb24sIEkndmUgdXNlZCBhIGNvcnB1cyBvZiBTaGFrZXNwZWFyZSdzIHBsYXlzIGFuZCBhZGFwdGVkIHNvbWUgY29kZSBmcm9tIFthIEthZ2dsZSBub3RlYm9va10oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9zaW5kaHVlZS9sb3ZlLWluLXNoYWtlc3BlYXJlP3NjcmlwdFZlcnNpb25JZD0xMTIxMjcwKS4KCmBgYHtyLG1lc3NhZ2U9RkFMU0UsY29sbGFwc2U9VFJVRX0KIyBSIG11c3QgYmUgYXQgbGVhc3QgMy4zLjEgZm9yIGB0bWAgYW5kIGBzbGFtYCB0byB3b3JrLgojIGluc3RhbGwucGFja2FnZXMoInRtIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJTbm93YmFsbEMiKQpsaWJyYXJ5KHRtKQojc3lzdGVtKCJscyAuLi9pbnB1dCIpICMgZG8gd2UgbmVlZCB0aGlzPwpgYGAKCkJlZm9yZSB3ZSBnZXQgaW50byBhbnl0aGluZyBmdW4sIHdlIGhhdmUgdG8gc2VlIHdoYXQgdGhlIGNvcnB1cyBsb29rcyBsaWtlOyB0aGF0IGlzLCBob3cgdGhlIGRhdGEgZnJhbWUgaXMgc3RydWN0dXJlZC4gVGhlc2UgYXJlIHRoZSBmaXJzdCBzaXggbGluZXMgb2YgdGhlIGNvcnB1cy4gKipOQjogdGhlcmUgaXMgY3VycmVudGx5IGEgc21hbGwgYnVnIGluIHRoZSBzb2Z0d2FyZSB0aGF0IHByZXZlbnRzIHRoZSBkYXRhIGZyb20gYmVpbmcgc2hvd24gbmVhdGx5LiBJdCBzaG91bGQgYmUgZml4ZWQgc29vbi4qKgoKYGBge3J9CnNoYWs8LXJlYWQuY3N2KCIuLi9kYXRhL1NoYWtlc3BlYXJlX2RhdGEuY3N2IixoZWFkZXIgPSBUUlVFLCBhcy5pcyA9IFRSVUUpCiNzaGFrPC1uYS5vbWl0KHNoYWspCmhlYWQoc2hhaykKYGBgCgpFYWNoIGNvbHVtbiBpcyBsYWJlbGVkIGFuZCB0aGUgY29udGVudCBvZiB0aGUgY29sdW1uIGlzIGNvbnNpc3RlbnQgZm9yIGVhY2ggcm93IChhbGwgMTExMzk2IG9mIHRoZW0hKS4gU29tZSBvZiB0aGUgcm93cyBtYXkgbm90IGJlIHVzZWZ1bC4gU29tZSBjb250YWluIGVtcHR5IGNlbGxzIChsYWJlbGVkIGBOQWApLiBTb21lIGNvbnRhaW4gYSBsb3Qgb2YgaW5mb3JtYXRpb24gYW5kIHdlIG1pZ2h0IG5lZWQgdG8gZG8gc29tZSBwcm9jZXNzaW5nIG9uIHRoZW0gYmVmb3JlIHdlIGNhbiB1c2UgdGhlIGluZm9ybWF0aW9uIHF1YW50aXRhdGl2ZWx5LgoKIyBXb3JkIGZyZXF1ZW5jeQoKVGhlIGZpcnN0IHRoaW5nIHdlJ2xsIGxvb2sgYXQgaXMgd29yZCBmcmVxdWVuY3ksIG9yIGhvdyBvZnRlbiBhIHN0cmluZyAoaW4gdGhpcyBjYXNlICJsb3ZlIikgb2NjdXJzIGluIHRoZSBkYXRhIGZyYW1lLiBUbyBkbyB0aGlzLCB3ZSBtdXN0IGlkZW50aWZ5IGV2ZXJ5IHRpbWUgdGhlIHdvcmQgImxvdmUiIGFwcGVhcnMgYW5kIGhpZ2hsaWdodCBpdCBpbiBhIHdheSBzbyB0aGF0IGl0IGNhbiBiZSBjb3VudGVkIGJhc2VkIG9uIGRpZmZlcmVudCBwcm9wZXJ0aWVzIG9mIGl0cyBlbnZpcm9ubWVudCAoZS5nLiwgYnkgcGxheSwgYnkgcGxheWVyLCBieSBzY2VuZSwgZXRjKS4KCkhlcmUgYXJlIHRoZSBmaXJzdCAxMCByb3dzIG9mIGEgZGF0YSBmcmFtZSB0aGF0IGNvbnRhaW5zIHRoZSBudW1iZXIgb2YgdGltZXMgImxvdmUiIGFwcGVhcnMgaW4gZWFjaCBwbGF5LiBJdCdzIGJlZW4gc29ydGVkIGluIGRlc2NlbmRpbmcgb3JkZXIsIGJ1dCBkb2Vzbid0IGNvbnRhaW4gYW55IG90aGVyIGluZm9ybWF0aW9uIGFib3V0IHdoZXJlIGFuZCB3aGVuIHRoZSB3b3JkIG9jY3Vycy4KCmBgYHtyfQojIHBsYXkgbGV2ZWwgd29yZCBmcmVxdWVuY3kKcGxheXMgPC0gdW5pcXVlKHNoYWskUGxheSkKbG92ZUZyZXE8LW51bWVyaWMoKQoKZm9yIChpIGluIDE6bGVuZ3RoKHBsYXlzKSl7CiAgICB0ZXh0IDwtIENvcnB1cyhWZWN0b3JTb3VyY2UocGFzdGUoc2hha1tzaGFrJFBsYXk9PXBsYXlzW2ldLF0kUGxheWVyTGluZSxjb2xsYXBzZT0iICIpKSkKICAgIHRleHQgPC0gdG1fbWFwKHRleHQsIHJlbW92ZVB1bmN0dWF0aW9uKQogICAgdGV4dCA8LSB0bV9tYXAodGV4dCwgUGxhaW5UZXh0RG9jdW1lbnQpCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCiAgICAKICAgICMgc3RlbW1pbmcgdG8gbWVyZ2UgYWxsICJsb3ZlZCIsICJsb3ZpbmciIGludG8gb25lICAgCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LCBzdGVtRG9jdW1lbnQpCiAgICB0ZG0gIDwtIFRlcm1Eb2N1bWVudE1hdHJpeCh0ZXh0KQogICAgCiAgICBsb3ZlRnJlcVtpXTwtYXMubnVtZXJpYyhzbGFtOjpyb3dfc3Vtcyh0ZG0pWyJsb3ZlIl0pCiAgfQoKbFBsYXkgPC0gZGF0YS5mcmFtZShwbGF5cyxsb3ZlRnJlcSkKbFBsYXkgPC0gbmEub21pdChsUGxheSkKCiMgb3JkZXIgdGhlIHBsYXlzIGJhc2VkIG9uIHRoZSBvY2N1cmVuY2Ugb2YgbG92ZQpsUGxheTwtbFBsYXlbb3JkZXIoLWxQbGF5JGxvdmVGcmVxKSxdCmhlYWQobFBsYXksMTApCmBgYAoKV2UgY2FuIGFsc28gbG9vayBhdCB3aGljaCBwbGF5ZXJzIHNheSAibG92ZSIgdGhlIG1vc3Qgb3ZlciB0aGUgY291cnNlIG9mIHRoZWlyIGFwcGVhcmVuY2VzLiBUaGVzZSBhcmUgb25seSB0aGUgdG9wIDEwIHBsYXllcnMgd2hvIHVzZSB0aGUgd29yZCAibG92ZSIgbW9zdC4gCgpgYGB7cn0KIyBwbGF5ZXIgbGV2ZWwgd29yZCBmcmVxdWVuY3kKcGxheWVycyA8LSB1bmlxdWUoc2hhayRQbGF5ZXIpCmxvdmVGcmVxIDwtIG51bWVyaWMoKQoKZm9yIChpIGluIDE6bGVuZ3RoKHBsYXllcnMpKXsKICAgIHRleHQgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShwYXN0ZShzaGFrW3NoYWskUGxheWVyPT1wbGF5ZXJzW2ldLF0kUGxheWVyTGluZSxjb2xsYXBzZT0iICIpKSkKICAgIHRleHQgPC0gdG1fbWFwKHRleHQsIHJlbW92ZVB1bmN0dWF0aW9uKQogICAgdGV4dCA8LSB0bV9tYXAodGV4dCwgUGxhaW5UZXh0RG9jdW1lbnQpCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCiAgICB0ZXh0IDwtIHRtX21hcCh0ZXh0LHN0ZW1Eb2N1bWVudCkKICAgIAogICAgdGRtICA8LSBUZXJtRG9jdW1lbnRNYXRyaXgodGV4dCkKICAgIAogICAgbG92ZUZyZXFbaV0gPC0gYXMubnVtZXJpYyhzbGFtOjpyb3dfc3Vtcyh0ZG0pWyJsb3ZlIl0pCiAgfQoKbFBsYXllciA8LSBkYXRhLmZyYW1lKHBsYXllcnMsbG92ZUZyZXEpCmxQbGF5ZXIgPC0gbmEub21pdChsUGxheWVyKQojb3JkZXIKbFBsYXllciA8LSBsUGxheWVyW29yZGVyKC1sUGxheWVyJGxvdmVGcmVxKSxdCgpoZWFkKGxQbGF5ZXIsMTApCmBgYAoKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgYm90dG9tIG9mIHRoZSBsaXN0LiBUaGVzZSBhcmUgMTAgcGxheWVycyB3aG8gb25seSBzYXkgImxvdmUiIG9uY2UsIGFsdGhvdWdoIHRoZXJlIGFyZSBsaWtlbHkgbWFueSBvdGhlcnMgd2hvIGFyZSBhbHNvIHRpZWQgZm9yIGxhc3QuCgpgYGB7cn0KdGFpbChsUGxheWVyLDEwKQpgYGAKCklzIHRoaXMgdXNlZnVsIHRvIHlvdT8gQ2FuIHdvcmQgZnJlcXVlbmN5IGJ5IGNoYXJhY3Rlci9wbGF5ZXIsIHNjZW5lLCBhY3QsIHBsYXksIG9yIGF1dGhvciBoZWxwIHRvIGFuc3dlciBhbnkgb2YgeW91ciByZXNlYXJjaCBxdWVzdGlvbnM/CgojIFZpc3VhbGlzaW5nIGEgY29ycHVzCgpJIHRoaW5rIHRoZSBtYWluIHdheSBxdWFudGl0YXRpdmUgYW5hbHlzaXMgY2FuIGJlIG9mIHVzZSB0byB0aGUgaHVtYW5pdGllcyBpcyBieSB2aXN1YWxpc2luZyBwcm9wZXJ0aWVzIG9mIHRoZSB0ZXh0IHRoYXQgbWlnaHQgbm90IGJlIGltbWVkaWF0ZWx5IGFwcGFyZW50IGZyb20gcmVhZGluZy4gV29yZCBmcmVxdWVuY3kgaXMgb25lIG9mIHRoZXNlIHByb3BlcnRpZXMsIHNpbmNlIHdlIChhcyBodW1hbnMpIGRvbid0IHR5cGljYWxseSBrZWVwIHRyYWNrIG9mIGhvdyBvZnRlbiBlYWNoIGNoYXJhY3RlcnMgc2F5cyBhbnkgZ2l2ZW4gd29yZC4gSWYgeW91J3JlIGludGVyZXN0ZWQgaW4gaG93IGRpZmZlcmVudCBjaGFyYWN0ZXJzIG9yIGRpZmZlcmVudCBhdXRob3JzIG1ha2UgdXNlIG9mIGNlcnRhaW4gd29yZHMgb3IgcGhyYXNlcywgdmlzdWFsaXNpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aG9zZSBzdHJpbmdzIG1pZ2h0IHVuY292ZXIgcGF0dGVybnMgdGhhdCBhcmUgb3RoZXJ3aXNlIGRpZmZpY3VsdCB0byBmaW5kLgoKRm9yIGluc3RhbmNlLCBtYXliZSB5b3UgYXJlIGN1cmlvdXMgaG93IHRoZSBsb25nZXIgYW5kIHNob3J0ZXIgcGxheXMgY29tcGFyZS4gSW5zdGVhZCBvZiBoYW5kLWNvdW50aW5nIGVhY2gsIHdlIGNhbiBncmFwaCBhbmQgb3JkZXIgdGhlbS4gQmFzZWQgb24gdGhpcyBncmFwaCwgeW91IGRvbid0IG5lZWQgdG8ga25vdyBleGFjdGx5IGhvdyBsb25nIGVhY2ggaXMsIGJ1dCB5b3UgY2FuIHNlZSB0aGF0ICpPdGhlbGxvKiBpcyBtdWNoIGxvbmdlciB0aGFuICpMb3ZlcyBMYWJvdXJzIExvc3QqLCB3aGljaCBjYW4gaW5mb3JtIGhvdyB5b3UgYXBwcm9hY2ggdGhlIGNvbXBhcmlzb24uCgpgYGB7cn0Kc2hhayAlPiUKICBncm91cF9ieShQbGF5KSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyh4PXJlb3JkZXIoUGxheSwgbikseT1uKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiTGVuZ3RoIG9mIFNoYWtlc3BlYXJlJ3MgcGxheXMiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB4bGFiKCJQbGF5IikgKwogICAgeWxhYigiTnVtYmVyIG9mIGxpbmVzIikKYGBgCgpXaXRoaW4gYSBzaW5nbGUgcGxheSwgbWF5YmUgd2Ugd2FudCB0byBrbm93IHdoaWNoIGNoYXJhY3RlcnMgYXJlIHRoZSBjaGF0dGllc3QuIFdlIGNhbiB2aXN1YWxpc2UgdGhlIG51bWJlciBvZiBsaW5lcyBvZiB0ZXh0IHBlciBjaGFyYWN0ZXIgdG8gZ2V0IGEgc2Vuc2Ugb2Ygd2hvIGlzIGRvbWluYXRpbmcgdGhlIHN0YWdlLgoKYGBge3J9CnNoYWsgJT4lCiAgZmlsdGVyKFBsYXkgPT0gIkhhbWxldCIpICU+JQogIGdyb3VwX2J5KFBsYXllcikgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQogIGdncGxvdCguLCBhZXMoeD1yZW9yZGVyKFBsYXllciwgbikseT1uKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiU3BlZWNoIGluIEhhbWxldCIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAgIHhsYWIoIlBsYXllciIpICsKICAgIHlsYWIoIk51bWJlciBvZiBsaW5lcyIpCmBgYAoKT2J2aW91c2x5LCBpdCdzIEhhbWxldC4KCmBgYHtyfQpzaGFrICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiKSAlPiUKICBncm91cF9ieShQbGF5ZXIpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9cmVvcmRlcihQbGF5ZXIsIG4pLHk9bikpICsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGdndGl0bGUoIlNwZWVjaCBpbiBIYW1sZXQiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB4bGFiKCJQbGF5ZXIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgbGluZXMgKGxvZ2FyaXRobWljIHNjYWxlKSIpICsKICAgIHNjYWxlX3lfbG9nMTAoKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGdyb3VwX2J5KFBsYXksUGxheWVyKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgZmlsdGVyKG4gPiA3MDApICU+JQogIGdncGxvdCguLCBhZXMoeD1yZW9yZGVyKFBsYXllciwgbikseT1uKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9UGxheSksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiQW1vdW50IG9mIGxpbmVzIGJ5IGNoYXJhY3RlciIpICsKIyAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB4bGFiKCJQbGF5ZXIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgbGluZXMiKQpgYGAKCmBgYHtyfQpsUGxheSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9cmVvcmRlcihwbGF5cywgbG92ZUZyZXEpLHk9bG92ZUZyZXEpKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD1wbGF5cyksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiTG92ZSBpbiBlYWNoIHBsYXkiKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICAgeGxhYigiUGxheSIpICsKICAgIHlsYWIoImZyZXF1ZW5jeSBvZiB0aGUgd29yZCAnbG92ZSciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKYGBge3J9CmxQbGF5ZXIgJT4lCiAgZmlsdGVyKGxvdmVGcmVxID4gMjApICU+JQogIGdncGxvdCguLCBhZXMoeD1yZW9yZGVyKHBsYXllcnMsIGxvdmVGcmVxKSx5PWxvdmVGcmVxKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9cGxheWVycyksc3RhdD0iaWRlbnRpdHkiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZ2d0aXRsZSgiTG92ZSBpbiBlYWNoIHBsYXkiKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICAgeGxhYigiUGxheSIpICsKICAgIHlsYWIoImZyZXF1ZW5jeSBvZiB0aGUgd29yZCAnbG92ZSciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyBBdHRlbXB0aW5nIG4tZ3JhbXMKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXRleHQiKQpsaWJyYXJ5KHRpZHl0ZXh0KQpgYGAKCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoLikgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICB1bm5lc3RfdG9rZW5zKHRibD0uLCBpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IHdvcmQpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQpgYGAKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICB1bm5lc3RfdG9rZW5zKHRibD0uLCBpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IHdvcmQpICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKYGBgCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoLikgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQogIGZpbHRlcihuPjgwMCkgJT4lCiAgZ2dwbG90KC4sIGFlcyh4PXJlb3JkZXIod29yZCxuKSx5PW4pKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgIGNvb3JkX2ZsaXAoKQpgYGAKCiMjIFVzaW5nIHRpYmJsZXMKCkhvdyBjYW4gd2Ugb3JnYW5pc2UgdGhpcyBzbyB0aGF0IHdlIGNhbiBjb21wYXJlIGFjcm9zcyBwbGF5cz8KCmBgYHtyfQpzaGFrWyxjKDIsNSw2KV0gJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2Vucyh0Ymw9LiwgaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB3b3JkKSAlPiUKICBmaWx0ZXIod29yZD09ImxvdmUiIHwgd29yZCA9PSJraW5nIiB8IHdvcmQ9PSJkZWF0aCIgfCB3b3JkPT0ic3dlZXQiKSAlPiUKICAjYWRkX2NvdW50KFBsYXllcikgJT4lCiAgZ3JvdXBfYnkoUGxheWVyLFBsYXksd29yZCkgJT4lCiAgc3VtbWFyaXNlKG49bigpKSAlPiUKICAjYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQogIGZpbHRlciggIFBsYXkgPT0gIkhhbWxldCIgfCAKICAgICAgICAgICBQbGF5ID09ICJLaW5nIExlYXIiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQSBNaWRzdW1tZXIgbmlnaHRzIGRyZWFtIiB8IAogICAgICAgICAgIFBsYXkgPT0gIk90aGVsbG8iIHwgCiAgICAgICAgICAgUGxheSA9PSAiSGVucnkgViIgfCAKICAgICAgICAgICBQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IikgJT4lCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9d29yZCx5PW4pKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD13b3JkKSxzdGF0PSJpZGVudGl0eSIpICsKIyAgICBjb29yZF9mbGlwKCkgKwogICAgZmFjZXRfd3JhcCh+UGxheSkKYGBgCgpJcyB0aGVyZSBhIHdheSB0byBicmVhayBpdCBkb3duIHRvIHNlZSB3aG8gaXMgc2F5aW5nIHdoYXQ/CgojIyBXaGF0IGFib3V0IG4tZ3JhbXMKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS41fQoKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gYmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lCiAgI2FudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIoYmlncmFtPT0ibXkgbG9yZCIgfCBiaWdyYW0gPT0ibXkgbGFkeSIgfCBiaWdyYW09PSJteSBtb3RoZXIiIHwgYmlncmFtPT0ibXkgZmF0aGVyIiB8IGJpZ3JhbT09Im15IHdpZmUiIHwgYmlncmFtPT0ibXkgaHVzYmFuZCIpICU+JQogIG11dGF0ZShnZW5kZXIgPSBiaWdyYW0pICU+JQogIG11dGF0ZShnZW5kZXIgPSByZWNvZGVfZmFjdG9yKGdlbmRlciwKICAgICAgICAgICAgICAgIGBteSBsb3JkYD0ibWFzYyIsCiAgICAgICAgICAgICAgICBgbXkgZmF0aGVyYD0ibWFzYyIsCiAgICAgICAgICAgICAgICBgbXkgaHVzYmFuZGA9Im1hc2MiLAogICAgICAgICAgICAgICAgYG15IGxhZHlgPSJmZW0iLAogICAgICAgICAgICAgICAgYG15IG1vdGhlcmA9ImZlbSIsCiAgICAgICAgICAgICAgICBgbXkgd2lmZWA9ImZlbSIpKSAlPiUKICBncm91cF9ieShQbGF5ZXIsUGxheSxiaWdyYW0sZ2VuZGVyKSAlPiUKICBzdW1tYXJpc2Uobj1uKCkpICU+JQogIG11dGF0ZShiaWdyYW1GYWMgPSBmYWN0b3IoYmlncmFtLCBsZXZlbHM9YygibXkgbG9yZCIsICJteSBodXNiYW5kIiwgIm15IGZhdGhlciIsICJteSBsYWR5IiwgIm15IHdpZmUiLCAibXkgbW90aGVyIikpKSAlPiUKICAjIHRvbyBib3JpbmcKICBmaWx0ZXIoICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDEiICYKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDIiICYKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSSBQYXJ0IDMiICYKICAgICAgICAgICBQbGF5ICE9ICJQZXJpY2xlcyIgJiAKICAgICAgICAgICBQbGF5ICE9ICJUaW1vbiBvZiBBdGhlbnMiICYgCiAgICAgICAgICAgUGxheSAhPSAiVGhlIFRlbXBlc3QiKSAlPiUKICAjIHRvbyBza2V3ZWQKICBmaWx0ZXIoICBQbGF5ICE9ICJIYW1sZXQiICYKICAgICAgICAgICBQbGF5ICE9ICJUcm9pbHVzIGFuZCBDcmVzc2lkYSIgJgogICAgICAgICAgIFBsYXkgIT0gIlJpY2hhcmQgSUlJIiAmCiAgICAgICAgICAgUGxheSAhPSAiVGl0dXMgQW5kcm9uaWN1cyIgJiAKICAgICAgICAgICBQbGF5ICE9ICJIZW5yeSBWSUlJIiAmIAogICAgICAgICAgIFBsYXkgIT0gIk11Y2ggQWRvIGFib3V0IG5vdGhpbmciKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGdncGxvdCguLCBhZXMoeD1iaWdyYW1GYWMseT1uKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGw9Z2VuZGVyKSxzdGF0PSJpZGVudGl0eSIpKyMscG9zaXRpb249ImRvZGdlIikgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBmYWNldF93cmFwKH5QbGF5LG5yb3c9MykKYGBgCgpgYGB7cn0Kc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gbmdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBtdXRhdGUoYmlncmFtID0gbmdyYW0pICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBuZ3JhbSwgb3V0cHV0ID0gd29yZCkgJT4lCiAgI2FudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIod29yZD09ImtpbmciIHwgd29yZD09InF1ZWVuIikgJT4lCiAgZ3JvdXBfYnkoUGxheSxiaWdyYW0sd29yZCkgJT4lCiAgc3VtbWFyaXNlKG49bigpKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGdncGxvdChhZXMoeD1yZW9yZGVyKFBsYXksbikpKSArCiAgICBnZW9tX2JhcihhZXMoZmlsbD13b3JkKSxzdGF0PSJjb3VudCIscG9zaXRpb249ImRvZGdlIikgKwogICAgI3NjYWxlX3lfbG9nMTAoKSArCiAgICBjb29yZF9mbGlwKCkKYGBgCgoKYGBge3J9CndvcmQgPC0gYyhOQSwidGhvdSIsInRoZWUiLCJ0aHkiLCJ0aGluZSIsImRvc3QiLCJzaGFsdCIsIndpbHQiLCJoYXN0IiwiaGF0aCIsInNjZW5lIiwidGlzIiwiaWkiLCJpaWkiLCJpdiIsInYiLCJ2aSIsInZpaSIpCmxleGljb24gPC0gcmVwKCJzaGFrZXNwZWFyZSIsbGVuZ3RoKHdvcmQpKQpuZXdfc3RvcCA8LSBjYmluZCh3b3JkLGxleGljb24pCnNoYWtfc3RvcCA8LSByYmluZChuZXdfc3RvcCxzdG9wX3dvcmRzKQpgYGAKCgoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKQpgYGAKCiMjIE5ldHdvcmtzCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoImlncmFwaCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3JhcGgiKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoZ3JpZCkKYGBgCgojIyMgQmlncmFtcwoKYGBge3J9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gYmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lCiAgc2VwYXJhdGUoYmlncmFtLCBjKCJ3b3JkMSIsICJ3b3JkMiIpLCBzZXAgPSAiICIpICU+JSAjIHNlcGFyYXRlcyBiaWdyYW0gaW50byB0d28gY29sdW1ucywgb25lIGZvciBlYWNoIHdvcmQKICBmaWx0ZXIoIXdvcmQxICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIGZpcnN0IGNvbHVtbgogIGZpbHRlcighd29yZDIgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gc2Vjb25kIGNvbHVtbgogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpICU+JQogIGZpbHRlcihuID4gMjIpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2JsdWUiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKQpgYGAKCgoKYGBge3J9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKcDEgPC0gc2hhayAlPiUKICBmaWx0ZXIoUGxheT09IkhhbWxldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiA2KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKCnNldC5zZWVkKDgxNCkKcDIgPC0gc2hhayAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiA2KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtyZWQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gInNhbG1vbiIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKQoKc2V0LnNlZWQoODE0KQpwMyA8LSBzaGFrICU+JQogIGZpbHRlcihQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IikgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKSAlPiUKICBmaWx0ZXIobiA+IDYpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2dyZWVuIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJncmVlbjIiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKCm11bHRpcGxvdChwMSxwMixwMyxjb2xzPTMpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9LjV9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKcDEgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheT09IkhhbWxldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgZ2d0aXRsZSgiSGFtbGV0IikKCnNldC5zZWVkKDgxNCkKcDIgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtyZWQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gInNhbG1vbiIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICBnZ3RpdGxlKCJUd2VsZnRoIE5pZ2h0IikKCnNldC5zZWVkKDgxNCkKcDMgPC0gc2hhayAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiUm9tZW8gYW5kIEp1bGlldCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtncmVlbiIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAiZ3JlZW4yIiwgc2l6ZSA9IDUpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpICsKICAgIGdndGl0bGUoIlJvbWVvIGFuZCBKdWxpZXQiKQoKc2V0LnNlZWQoODE0KQpwNCA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJPdGhlbGxvIikgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IFBsYXllckxpbmUsIG91dHB1dCA9IGJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKSAlPiUKICBmaWx0ZXIobiA+IDMpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya29yYW5nZSIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAib3JhbmdlIiwgc2l6ZSA9IDUpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpICsKICAgIGdndGl0bGUoIk90aGVsbG8iKQoKc2V0LnNlZWQoODE0KQpwNSA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJIZW5yeSBJViIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImNhZGV0Ymx1ZTQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgIGFycm93ID0gYSwgZW5kX2NhcCA9IGNpcmNsZSguMDcsICdpbmNoZXMnKSkgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImN5YW4iLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgZ2d0aXRsZSgiSGVucnkgSVYiKQoKc2V0LnNlZWQoODE0KQpwNiA8LSBzaGFrICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIGZpbHRlcihQbGF5ID09ICJUaGUgVGVtcGVzdCIpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSBiaWdyYW0sIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAzKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9InZpb2xldCIsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibWFnZW50YSIsIHNpemUgPSA1KSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWw9VFJVRSkgKyAjICwgdmp1c3QgPSAxLCBoanVzdCA9IDEpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICBnZ3RpdGxlKCJUaGUgVGVtcGVzdCIpCgptdWx0aXBsb3QocDEscDIscDMscDQscDUscDYsY29scz0zKQpgYGAKCiMjIyBUcmlncmFtcwoKVGhpcyBzaG91bGQgZ2l2ZSB1cyBhIGJldHRlciBpZGVhIG9mIHNsaWdodGx5IGxvb3NlciBjb25uZWN0aW9ucwoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9LjV9CnNldC5zZWVkKDgxNCkKYSA8LSBncmlkOjphcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlPTIyLjUsIGxlbmd0aCA9IHVuaXQoLjEsICJpbmNoZXMiKSkKc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gdHJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDMpICU+JQogIHNlcGFyYXRlKHRyaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiwgIndvcmQzIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgZmlsdGVyKCF3b3JkMyAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSB0aGlyZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHdvcmQzLCBzb3J0ID0gVFJVRSkgJT4lCiAgZmlsdGVyKG4gPiAyKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgZWRnZV9jb2xvdXI9ImRhcmtibHVlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGEsIGVuZF9jYXAgPSBjaXJjbGUoLjA3LCAnaW5jaGVzJykpICsKICAgIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gNSkgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsPVRSVUUpICsgIyAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSArCiAgICB0aGVtZV92b2lkKCkKYGBgCgoKV2hhdCBoYXBwZW5zIGlmIHdlIHRyZWF0IHRoZSBmaXJzdCBwYWlyIGFuZCBzZWNvbmQgcGFpciBvZiB0cmlncmFtcyBhcyBzZXBhcmF0ZSBiaWdyYW1zIGFuZCBncmFwaCB0aGVtIGFzIGJlZm9yZT8KCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS43NX0Kc2V0LnNlZWQoODE0KQphIDwtIGdyaWQ6OmFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGU9MjIuNSwgbGVuZ3RoID0gdW5pdCguMDc1LCAiaW5jaGVzIikpCncxdzIgPC0gc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gUGxheWVyTGluZSwgb3V0cHV0ID0gdHJpZ3JhbSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDMpICU+JQogIHNlcGFyYXRlKHRyaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiwgIndvcmQzIiksIHNlcCA9ICIgIikgJT4lICMgc2VwYXJhdGVzIGJpZ3JhbSBpbnRvIHR3byBjb2x1bW5zLCBvbmUgZm9yIGVhY2ggd29yZAogIGZpbHRlcighd29yZDEgJWluJSBzaGFrX3N0b3Akd29yZCkgJT4lICMgZmlsdGVycyBzdG9wIHdvcmRzIGZyb20gZmlyc3QgY29sdW1uCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBzZWNvbmQgY29sdW1uCiAgZmlsdGVyKCF3b3JkMyAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSB0aGlyZCBjb2x1bW4KICBjb3VudCh3b3JkMSwgd29yZDIsIHdvcmQzLCBzb3J0ID0gVFJVRSkgJT4lCiAgbXV0YXRlKHNldCA9IDEpICU+JQogIHRyYW5zbXV0ZSh3b3JkMT13b3JkMSx3b3JkMj13b3JkMixuPW4sc2V0PXNldCkKdzJ3MyA8LSBzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIHVubmVzdF90b2tlbnMoaW5wdXQgPSBQbGF5ZXJMaW5lLCBvdXRwdXQgPSB0cmlncmFtLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMykgJT4lCiAgc2VwYXJhdGUodHJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiLCAid29yZDMiKSwgc2VwID0gIiAiKSAlPiUgIyBzZXBhcmF0ZXMgYmlncmFtIGludG8gdHdvIGNvbHVtbnMsIG9uZSBmb3IgZWFjaCB3b3JkCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHNoYWtfc3RvcCR3b3JkKSAlPiUgIyBmaWx0ZXJzIHN0b3Agd29yZHMgZnJvbSBmaXJzdCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQyICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHNlY29uZCBjb2x1bW4KICBmaWx0ZXIoIXdvcmQzICVpbiUgc2hha19zdG9wJHdvcmQpICU+JSAjIGZpbHRlcnMgc3RvcCB3b3JkcyBmcm9tIHRoaXJkIGNvbHVtbgogIGNvdW50KHdvcmQxLCB3b3JkMiwgd29yZDMsIHNvcnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoc2V0ID0gMikgJT4lCiAgdHJhbnNtdXRlKHdvcmQxPXdvcmQyLHdvcmQyPXdvcmQzLG49bixzZXQ9c2V0KQp3WHdZIDwtIGJpbmRfcm93cyh3MXcyLHcydzMpCgp3WHdZICU+JQogIGZpbHRlcihuPj0zKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4pLCBlZGdlX2NvbG91cj0iZGFya2JsdWUiLCBzaG93LmxlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgYWxwaGE9Ljc1LCByZXBlbD1UUlVFKSArICMgLCB2anVzdCA9IDEsIGhqdXN0ID0gMSkgKwogICAgdGhlbWVfdm9pZCgpCmBgYAoKIyBIZWF0bWFwcwoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgI2ZpbHRlcihQbGF5ID09ICJIYW1sZXQiIHwgUGxheSA9PSAiTG92ZXMgTGFib3VycyBMb3N0IiB8IFBsYXkgPT0gIkEgV2ludGVycyBUYWxlIikgJT4lCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5udW1lcmljKGFjdCksIHNjZW5lPWFzLm51bWVyaWMoc2NlbmUpLCBuPW4pCmBgYAoKCmBgYHtyfQpzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiIHwgUGxheSA9PSAiS2luZyBKb2huIiB8IFBsYXkgPT0gIlRoZSBUZW1wZXN0IiB8IAogICAgICAgICAgIFBsYXkgPT0gIkN5bWJlbGluZSIgfCBQbGF5ID09ICJNZWFzdXJlIGZvciBtZWFzdXJlIiB8IFBsYXkgPT0gIlRpbW9uIG9mIEF0aGVucyIgfCAKICAgICAgICAgICBQbGF5ID09ICJSaWNoYXJkIElJSSIgfCBQbGF5ID09ICJMb3ZlcyBMYWJvdXJzIExvc3QiIHwgUGxheSA9PSAiQSBXaW50ZXJzIFRhbGUiIHwgCiAgICAgICAgICAgUGxheSA9PSAiT3RoZWxsbyIgfCBQbGF5ID09ICJSb21lbyBhbmQgSnVsaWV0IiB8IFBsYXkgPT0gIkhlbnJ5IFYiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5pbnRlZ2VyKGFjdCksIG49bikgJT4lCiAgZ2dwbG90KGFlcyh4PWFjdCx5PXJlb3JkZXIocGxheSwgbikpKSArIAogICAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbiksIGNvbG91ciA9ICJ3aGl0ZSIpICsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gInN0ZWVsYmx1ZSIpCmBgYAoKYGBge3J9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZmlsdGVyKFBsYXkgPT0gIkhhbWxldCIgfCBQbGF5ID09ICJLaW5nIEpvaG4iIHwgUGxheSA9PSAiVGhlIFRlbXBlc3QiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQ3ltYmVsaW5lIiB8IFBsYXkgPT0gIk1lYXN1cmUgZm9yIG1lYXN1cmUiIHwgUGxheSA9PSAiVGltb24gb2YgQXRoZW5zIiB8IAogICAgICAgICAgIFBsYXkgPT0gIlJpY2hhcmQgSUlJIiB8IFBsYXkgPT0gIkxvdmVzIExhYm91cnMgTG9zdCIgfCBQbGF5ID09ICJBIFdpbnRlcnMgVGFsZSIgfCAKICAgICAgICAgICBQbGF5ID09ICJPdGhlbGxvIiB8IFBsYXkgPT0gIlJvbWVvIGFuZCBKdWxpZXQiIHwgUGxheSA9PSAiSGVucnkgViIpICU+JSAKICBmaWx0ZXIoQWN0U2NlbmVMaW5lICE9ICIiKSAlPiUKICBtdXRhdGUoQWN0U2NlbmVMaW5lMiA9IEFjdFNjZW5lTGluZSkgJT4lCiAgc2VwYXJhdGUoQWN0U2NlbmVMaW5lMiwgYygiYWN0IiwgInNjZW5lIiwgImxpbmUiKSkgJT4lCiAgY291bnQoUGxheSxzY2VuZSwgc29ydD1UUlVFKSAlPiUKICB0cmFuc211dGUocGxheT1QbGF5LCBzY2VuZT1hcy5pbnRlZ2VyKHNjZW5lKSwgbj1uKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2NlbmUseT1yZW9yZGVyKHBsYXksIG4pKSkgKyAKICAgIGdlb21fdGlsZShhZXMoZmlsbCA9IG4pLCBjb2xvdXIgPSAid2hpdGUiKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJzdGVlbGJsdWUiKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMDo4KSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmFzcD0uMzV9CnNoYWsgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZmlsdGVyKFBsYXkgPT0gIkhhbWxldCIgfCBQbGF5ID09ICJLaW5nIEpvaG4iIHwgUGxheSA9PSAiVGhlIFRlbXBlc3QiIHwgCiAgICAgICAgICAgUGxheSA9PSAiQ3ltYmVsaW5lIiB8IFBsYXkgPT0gIk1lYXN1cmUgZm9yIG1lYXN1cmUiIHwgUGxheSA9PSAiVGltb24gb2YgQXRoZW5zIiB8IAogICAgICAgICAgIFBsYXkgPT0gIlJpY2hhcmQgSUlJIiB8IFBsYXkgPT0gIkxvdmVzIExhYm91cnMgTG9zdCIgfCBQbGF5ID09ICJBIFdpbnRlcnMgVGFsZSIgfCAKICAgICAgICAgICBQbGF5ID09ICJPdGhlbGxvIiB8IFBsYXkgPT0gIlJvbWVvIGFuZCBKdWxpZXQiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXksYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5PVBsYXksIGFjdD1hcy5pbnRlZ2VyKGFjdCksIHNjZW5lPWFzLmludGVnZXIoc2NlbmUpLCBuPW4pICU+JQogIGdncGxvdChhZXMoeD1zY2VuZSx5PXBsYXkpKSArIAogICAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbiksIGNvbG91ciA9ICJ3aGl0ZSIpICsgCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkMiIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwOjgpKSArCiAgICB0aGVtZV9kYXJrKCkgKyAKICAgIGZhY2V0X3dyYXAofmFjdCwgbmNvbCA9IDUpCmBgYAoKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuYXNwPS41fQpzaGFrICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGZpbHRlcihQbGF5ID09ICJIYW1sZXQiKSAlPiUgCiAgI2ZpbHRlcihQbGF5ZXIgIT0gIkhBTUxFVCIgJiBQbGF5ZXIgIT0gIkxPUkQgUE9MT05JVVMiICYgUGxheWVyICE9ICJLSU5HIENMQVVESVVTIikgJT4lIAogIGZpbHRlcihBY3RTY2VuZUxpbmUgIT0gIiIpICU+JQogIG11dGF0ZShBY3RTY2VuZUxpbmUyID0gQWN0U2NlbmVMaW5lKSAlPiUKICBzZXBhcmF0ZShBY3RTY2VuZUxpbmUyLCBjKCJhY3QiLCAic2NlbmUiLCAibGluZSIpKSAlPiUKICBjb3VudChQbGF5ZXIsYWN0LHNjZW5lLCBzb3J0PVRSVUUpICU+JQogIHRyYW5zbXV0ZShwbGF5ZXI9UGxheWVyLCBhY3Q9YXMuaW50ZWdlcihhY3QpLCBzY2VuZT1hcy5pbnRlZ2VyKHNjZW5lKSwgbj1uKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2NlbmUseT1yZW9yZGVyKHBsYXllcixuKSkpICsgCiAgICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBuKSwgY29sb3VyID0gIndoaXRlIikgKyAKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQyIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDA6OCkpICsKICAgIHRoZW1lX2RhcmsoKSArIAogICAgZmFjZXRfd3JhcCh+YWN0LCBuY29sID0gNSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmFzcD0uNX0Kc2hhayAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoUGxheSA9PSAiVHdlbGZ0aCBOaWdodCIpICU+JSAKICAjZmlsdGVyKFBsYXllciAhPSAiSEFNTEVUIiAmIFBsYXllciAhPSAiTE9SRCBQT0xPTklVUyIgJiBQbGF5ZXIgIT0gIktJTkcgQ0xBVURJVVMiKSAlPiUgCiAgZmlsdGVyKEFjdFNjZW5lTGluZSAhPSAiIikgJT4lCiAgbXV0YXRlKEFjdFNjZW5lTGluZTIgPSBBY3RTY2VuZUxpbmUpICU+JQogIHNlcGFyYXRlKEFjdFNjZW5lTGluZTIsIGMoImFjdCIsICJzY2VuZSIsICJsaW5lIikpICU+JQogIGNvdW50KFBsYXllcixhY3Qsc2NlbmUsIHNvcnQ9VFJVRSkgJT4lCiAgdHJhbnNtdXRlKHBsYXllcj1QbGF5ZXIsIGFjdD1hcy5pbnRlZ2VyKGFjdCksIHNjZW5lPWFzLmludGVnZXIoc2NlbmUpLCBuPW4pICU+JQogIGdncGxvdChhZXMoeD1zY2VuZSx5PXBsYXllcikpICsgCiAgICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBuKSwgY29sb3VyID0gIndoaXRlIikgKyAKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQyIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDA6OCkpICsKICAgIHRoZW1lX2RhcmsoKSArIAogICAgZmFjZXRfd3JhcCh+YWN0LCBuY29sID0gNSkKYGBgCgojIyBXcmFwIHVwCgpXaGF0IHRoaXMgYWxsIHNlZW1zIHRvIHRlbGwgdXMgaXMgdGhhdCB3ZSBjYW4gdmlzdWFsaXNlIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHBsYXksIHNlcGFyYXRlIGZyb20gdGhlaXIgY29udGVudC4gSXMgdGhpcyB1c2VmdWwgdG8geW91Pw==